﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Threading;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using TeenyGrab.Interfaces;
using TeenyGrab.Filters;
using TeenyGrab.Outputs;
using TeenyGrab.Helpers;
using TeenyGrab.Inputs;
using TeenyGrab.Serialization;
using TeenyGrab.Windows;
using MouseKeyboardActivityMonitor;
using MouseKeyboardActivityMonitor.WinApi;
using TeenyGrab.Classes;

namespace TeenyGrab
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private NotifyIcon TrayIcon { get; set; }
        private bool Exit { get; set; }
        private IInput Input { get; set; }
        private IFilter Filter { get; set; }
        private IOutput Output { get; set; }

        private List<Keys> Pressed { get; set; }
        private Hotkey DefaultHotkey { get; set; }

        private bool ShootingEnabled { get; set; }

        private readonly string Version = "1.0.2";

        private KeyboardHookListener KeyboardHookListener { get; set; }

        public MainWindow()
        {
            InitializeComponent();

            KeyboardHookListener = new KeyboardHookListener(new GlobalHooker());
            KeyboardHookListener.KeyUp += new System.Windows.Forms.KeyEventHandler(KeyboardHookListener_KeyUp);
            KeyboardHookListener.KeyDown += new System.Windows.Forms.KeyEventHandler(KeyboardHookListener_KeyDown);
            KeyboardHookListener.Enabled = true;

            Exit = false;
            ShootingEnabled = true;

            Pressed = new List<Keys>();

            this.Icon = BitmapFrame.Create(new Uri("pack://application:,,,/teenygrab.ico"));

            TrayIcon = new NotifyIcon();
            TrayIcon.Icon = new System.Drawing.Icon(System.Windows.Application.GetResourceStream(new Uri("pack://application:,,,/teenygrab.ico")).Stream);
            TrayIcon.MouseClick += new System.Windows.Forms.MouseEventHandler(TrayIcon_MouseClick);

            var settings = new SerializableSettings();
            if (File.Exists("settings.xml") && !File.Exists("settings.dat"))
            {
                File.Move("settings.xml", "settings.dat");
            }
            if (File.Exists("settings.dat"))
            {
                var bf = new BinaryFormatter();
                using (var fs = new FileStream("settings.dat", FileMode.Open))
                {
                    settings = (SerializableSettings)bf.Deserialize(fs);
                }
            }

            DefaultHotkey = settings.DefaultHotkey != null ? settings.DefaultHotkey : new Hotkey(Key.PrintScreen);

            var inputs = new List<IInput>()
                {
                    FindOrNew<IInput>(settings.Inputs, typeof(FullScreenInput)),
                    FindOrNew<IInput>(settings.Inputs, typeof(PartialScreenInput)),
                    FindOrNew<IInput>(settings.Inputs, typeof(WindowInput)),
                    FindOrNew<IInput>(settings.Inputs, typeof(BlankInput)),
                };
            comboBoxInput.ItemsSource = inputs;
            comboBoxInput.SelectedIndex = settings.SelectedInput != -1 ? settings.SelectedInput : 0;

            var filters = new List<IFilter>()
                {
                    FindOrNew<IFilter>(settings.Filters, typeof(DefaultFilter)),
                };
            comboBoxFilter.ItemsSource = filters;
            comboBoxFilter.SelectedIndex = settings.SelectedFilter != -1 ? settings.SelectedFilter : 0;

            var outputs = new List<IOutput>()
                {
                    FindOrNew<IOutput>(settings.Outputs, typeof(FileOutput)),
                    FindOrNew<IOutput>(settings.Outputs, typeof(FtpOutput)),
                    FindOrNew<IOutput>(settings.Outputs, typeof(ClipboardOutput)),
                    FindOrNew<IOutput>(settings.Outputs, typeof(ImgurOutput)),
                    FindOrNew<IOutput>(settings.Outputs, typeof(PopupOutput)),
                };
            comboBoxOutput.ItemsSource = outputs;
            comboBoxOutput.SelectedIndex = settings.SelectedOutput != -1 ? settings.SelectedOutput : 0;
        }

        private List<Keys> Modifiers = new List<Keys>() { Keys.LShiftKey, Keys.RShiftKey, Keys.Alt, Keys.LControlKey, Keys.RControlKey };
        void KeyboardHookListener_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            if (!Pressed.Contains(e.KeyCode))
            {
                Pressed.Add(e.KeyCode);
            }
        }

        void KeyboardHookListener_KeyUp(object sender, System.Windows.Forms.KeyEventArgs e)
        {
            if (IsHotkeyPressed(DefaultHotkey))
            {
                Go();
            }
            
            if (Pressed.Contains(e.KeyCode))
            {
                Pressed.Remove(e.KeyCode);
            }        
        }

        private bool IsHotkeyPressed(Hotkey hotkey)
        {
            return Pressed.Contains(hotkey.Button) &&
                  (Pressed.Contains(Keys.LShiftKey) || Pressed.Contains(Keys.RShiftKey)) == hotkey.Shift &&
                  (Pressed.Contains(Keys.LControlKey) || Pressed.Contains(Keys.RControlKey)) == hotkey.Ctrl &&
                  (Pressed.Contains(Keys.Alt)) == hotkey.Alt;
        }

        private T FindOrNew<T>(List<T> list, Type find)
        {
            if (list == null || list.Count == 0)
            {
                return (T)Activator.CreateInstance(find);
            }

            T input = default(T);
            return (input = list.Find(i => i.GetType() == find)) != null ? input : (T)Activator.CreateInstance(find);
        }

        private void TrayIcon_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            this.WindowState = System.Windows.WindowState.Normal;   
        }

        private void Window_StateChanged(object sender, EventArgs e)
        {
            if (this.WindowState == WindowState.Minimized)
            {
                this.ShowInTaskbar = false;
                TrayIcon.Visible = true;
            }
            else if (this.WindowState == WindowState.Normal || this.WindowState == WindowState.Maximized)
            {
                this.ShowInTaskbar = true;
                TrayIcon.Visible = false;
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            //if (!Exit)
            //{
            //    e.Cancel = true;
            //    this.WindowState = System.Windows.WindowState.Minimized;
            //}

            var bf = new BinaryFormatter();
            using (var fs = new FileStream("settings.dat", FileMode.Create))
            {
                bf.Serialize(fs, new SerializableSettings()
                {
                    DefaultHotkey = DefaultHotkey,
                    Inputs = new List<IInput>((IEnumerable<IInput>)comboBoxInput.ItemsSource),
                    Filters = new List<IFilter>((IEnumerable<IFilter>)comboBoxFilter.ItemsSource),
                    Outputs = new List<IOutput>((IEnumerable<IOutput>)comboBoxOutput.ItemsSource),
                    SelectedInput = comboBoxInput.SelectedIndex,
                    SelectedFilter = comboBoxFilter.SelectedIndex,
                    SelectedOutput = comboBoxOutput.SelectedIndex,
                });
            }
        }

        private void buttonExit_Click(object sender, RoutedEventArgs e)
        {
            Exit = true;
            this.Close();
        }

        private void buttonManual_Click(object sender, RoutedEventArgs e)
        {
            Go();
        }

        private void Go()
        {
            if (ShootingEnabled)
            {
                var t = new Thread(new ThreadStart(GoThread));
                t.SetApartmentState(ApartmentState.STA);
                t.Start();
            }
        }
        
        private void GoThread()
        {
            var input = Input;
            var filter = Filter;
            var output = Output;

            var image = input.Get();
            if (image == null) return; // stop

            image = filter.Process(image);
            if (image == null) return; // stop

            output.Put(image);
        }

        private void buttonConfigureInput_Click(object sender, RoutedEventArgs e)
        {
            var input = (comboBoxInput.SelectedItem as IInput);
            if (input != null)
            {
                input.Configure();
            }
        }

        private void buttonConfigureFilter_Click(object sender, RoutedEventArgs e)
        {
            var filter = (comboBoxFilter.SelectedItem as IFilter);
            if (filter != null)
            {
                filter.Configure();
            }
        }

        private void buttonConfigureOutput_Click(object sender, RoutedEventArgs e)
        {
            var output = (comboBoxOutput.SelectedItem as IOutput);
            if (output != null)
            {
                output.Configure();
            }
        }

        private void comboBoxInput_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Input = (comboBoxInput.SelectedItem as IInput);
            if (comboBoxInput.SelectedItem != null)
            {
                var input = (comboBoxInput.SelectedItem as IInput);
                buttonConfigureInput.IsEnabled = input.Configurable;
            }
            else
            {
                buttonConfigureInput.IsEnabled = false;
            }
        }

        private void comboBoxFilter_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Filter = (comboBoxFilter.SelectedItem as IFilter);
            if (comboBoxFilter.SelectedItem != null)
            {
                var filter = (comboBoxFilter.SelectedItem as IFilter);
                buttonConfigureFilter.IsEnabled = filter.Configurable;
            }
            else
            {
                buttonConfigureFilter.IsEnabled = false;
            }
        }

        private void comboBoxOutput_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Output = (comboBoxOutput.SelectedItem as IOutput);
            if (comboBoxOutput.SelectedItem != null)
            {
                var output = (comboBoxOutput.SelectedItem as IOutput);
                buttonConfigureOutput.IsEnabled = output.Configurable;
            }
            else
            {
                buttonConfigureOutput.IsEnabled = false;
            }
        }

        private void buttonConfigureHotkeys_Click(object sender, RoutedEventArgs e)
        {
            ShootingEnabled = false;
            var config = new ConfigureHotkeyWindow(DefaultHotkey);
            config.Closed += new EventHandler((x, y) => { ShootingEnabled = true; });
            config.ShowDialog();
        }
    }
}
